package com.ws.universal.tools.utils;

import android.util.Log;

import androidx.annotation.NonNull;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * <pre>
 *     author: Blankj
 *     blog  : http://blankj.com
 *     time  : 2016/08/07
 *     desc  : utils about shell
 * </pre>
 */
public final class ShellUtils {
    public static final String TAG = "CommandExecution";
    public final static String COMMAND_SU = "su";
    public final static String COMMAND_SH = "sh";
    public final static String COMMAND_EXIT = "exit\n";
    public final static String COMMAND_LINE_END = "\n";

    // 获取ROOT权限
    public static void get_root() {
        try {
            Runtime.getRuntime().exec("su");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    // 判断是否具有ROOT权限
    public static boolean is_root() {
        boolean res = false;
        try {
            res = (new File("/system/bin/su").exists()) ||
                    (new File("/system/xbin/su").exists());
            ;
        } catch (Exception e) {
        }
        return res;
    }

    /**
     * 执行命令—单条
     *
     * @param command
     * @return
     */
    public static CommandResult execCmd(String command) {
        String[] commands = {command};
        return execCmd(commands);
    }

    /**
     * 执行命令-多条
     *
     * @param commands
     * @return
     */
    public static CommandResult execCmd(String[] commands) {
        CommandResult commandResult = new CommandResult();
        if (commands == null || commands.length == 0) return commandResult;
        Process process = null;
        DataOutputStream os = null;
        BufferedReader successResult = null;
        BufferedReader errorResult = null;
        StringBuilder successMsg = null;
        StringBuilder errorMsg = null;
        try {
            process = Runtime.getRuntime().exec(is_root() ? COMMAND_SU : COMMAND_SH);
            os = new DataOutputStream(process.getOutputStream());
            for (String command : commands) {
                if (command != null) {
                    os.write(command.getBytes());
                    os.writeBytes(COMMAND_LINE_END);
                    os.flush();
                }
            }
            os.writeBytes(COMMAND_EXIT);
            os.flush();
            commandResult.result = process.waitFor();
            //获取错误信息
            successMsg = new StringBuilder();
            errorMsg = new StringBuilder();
            successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
            errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            String s;
            while ((s = successResult.readLine()) != null) successMsg.append(s);
            while ((s = errorResult.readLine()) != null) errorMsg.append(s);
            commandResult.successMsg = successMsg.toString();
            commandResult.errorMsg = errorMsg.toString();
            Log.i(TAG, commandResult.result + " | " + commandResult.successMsg
                    + " | " + commandResult.errorMsg);
        } catch (IOException e) {
            String errmsg = e.getMessage();
            if (errmsg != null) {
                Log.e(TAG, errmsg);
            } else {
                e.printStackTrace();
            }
        } catch (Exception e) {
            String errmsg = e.getMessage();
            if (errmsg != null) {
                Log.e(TAG, errmsg);
            } else {
                e.printStackTrace();
            }
        } finally {
            try {
                if (os != null) os.close();
                if (successResult != null) successResult.close();
                if (errorResult != null) errorResult.close();
            } catch (IOException e) {
                String errmsg = e.getMessage();
                if (errmsg != null) {
                    Log.e(TAG, errmsg);
                } else {
                    e.printStackTrace();
                }
            }
            if (process != null) process.destroy();
        }
        return commandResult;
    }

    /**
     * Command执行结果
     *
     * @author Mountain
     */
    public static class CommandResult {
        public int result = -1;
        public String errorMsg;
        public String successMsg;

        @NonNull
        @Override
        public String toString() {
            return "result: " + result + "\n" +
                    "successMsg: " + successMsg + "\n" +
                    "errorMsg: " + errorMsg;
        }

    }


//    private static final String LINE_SEP = System.getProperty("line.separator");
//
//    private ShellUtils() {
//        throw new UnsupportedOperationException("u can't instantiate me...");
//    }
//
//    /**
//     * Execute the command asynchronously.
//     *
//     * @param command  The command.
//     * @param isRooted True to use root, false otherwise.
//     * @param consumer The consumer.
//     * @return the task
//     */
//    public static Utils.TaskNew<CommandResult> execCmdAsync(final String command,
//                                                            final boolean isRooted,
//                                                            final Utils.Consumer<CommandResult> consumer) {
//        return execCmdAsync(new String[]{command}, isRooted, true, consumer);
//    }
//
//    /**
//     * Execute the command asynchronously.
//     *
//     * @param commands The commands.
//     * @param isRooted True to use root, false otherwise.
//     * @param consumer The consumer.
//     * @return the task
//     */
//    public static Utils.TaskNew<CommandResult> execCmdAsync(final List<String> commands,
//                                                            final boolean isRooted,
//                                                            final Utils.Consumer<CommandResult> consumer) {
//        return execCmdAsync(commands == null ? null : commands.toArray(new String[]{}), isRooted, true, consumer);
//    }
//
//    /**
//     * Execute the command asynchronously.
//     *
//     * @param commands The commands.
//     * @param isRooted True to use root, false otherwise.
//     * @param consumer The consumer.
//     * @return the task
//     */
//    public static Utils.TaskNew<CommandResult> execCmdAsync(final String[] commands,
//                                                            final boolean isRooted,
//                                                            final Utils.Consumer<CommandResult> consumer) {
//        return execCmdAsync(commands, isRooted, true, consumer);
//    }
//
//    /**
//     * Execute the command asynchronously.
//     *
//     * @param command         The command.
//     * @param isRooted        True to use root, false otherwise.
//     * @param isNeedResultMsg True to return the message of result, false otherwise.
//     * @param consumer        The consumer.
//     * @return the task
//     */
//    public static Utils.TaskNew<CommandResult> execCmdAsync(final String command,
//                                                            final boolean isRooted,
//                                                            final boolean isNeedResultMsg,
//                                                            final Utils.Consumer<CommandResult> consumer) {
//        return execCmdAsync(new String[]{command}, isRooted, isNeedResultMsg, consumer);
//    }
//
//    /**
//     * Execute the command asynchronously.
//     *
//     * @param commands        The commands.
//     * @param isRooted        True to use root, false otherwise.
//     * @param isNeedResultMsg True to return the message of result, false otherwise.
//     * @param consumer        The consumer.
//     * @return the task
//     */
//    public static Utils.TaskNew<CommandResult> execCmdAsync(final List<String> commands,
//                                                            final boolean isRooted,
//                                                            final boolean isNeedResultMsg,
//                                                            final Utils.Consumer<CommandResult> consumer) {
//        return execCmdAsync(commands == null ? null : commands.toArray(new String[]{}),
//                isRooted,
//                isNeedResultMsg,
//                consumer);
//    }
//
//    /**
//     * Execute the command asynchronously.
//     *
//     * @param commands        The commands.
//     * @param isRooted        True to use root, false otherwise.
//     * @param isNeedResultMsg True to return the message of result, false otherwise.
//     * @param consumer        The consumer.
//     * @return the task
//     */
//    public static Utils.TaskNew<CommandResult> execCmdAsync(final String[] commands,
//                                                            final boolean isRooted,
//                                                            final boolean isNeedResultMsg,
//                                                            @NonNull final Utils.Consumer<CommandResult> consumer) {
//        return UtilsBridge.doAsync(new Utils.TaskNew<CommandResult>(consumer) {
//            @Override
//            public CommandResult doInBackground() {
//                return execCmd(commands, isRooted, isNeedResultMsg);
//            }
//        });
//    }
//
//    /**
//     * Execute the command.
//     *
//     * @param command  The command.
//     * @param isRooted True to use root, false otherwise.
//     * @return the single {@link CommandResult} instance
//     */
//    public static CommandResult execCmd(final String command, final boolean isRooted) {
//        return execCmd(new String[]{command}, isRooted, true);
//    }
//
//    /**
//     * Execute the command.
//     *
//     * @param command  The command.
//     * @param envp     The environment variable settings.
//     * @param isRooted True to use root, false otherwise.
//     * @return the single {@link CommandResult} instance
//     */
//    public static CommandResult execCmd(final String command, final List<String> envp, final boolean isRooted) {
//        return execCmd(new String[]{command},
//                envp == null ? null : envp.toArray(new String[]{}),
//                isRooted,
//                true);
//    }
//
//    /**
//     * Execute the command.
//     *
//     * @param commands The commands.
//     * @param isRooted True to use root, false otherwise.
//     * @return the single {@link CommandResult} instance
//     */
//    public static CommandResult execCmd(final List<String> commands, final boolean isRooted) {
//        return execCmd(commands == null ? null : commands.toArray(new String[]{}), isRooted, true);
//    }
//
//    /**
//     * Execute the command.
//     *
//     * @param commands The commands.
//     * @param envp     The environment variable settings.
//     * @param isRooted True to use root, false otherwise.
//     * @return the single {@link CommandResult} instance
//     */
//    public static CommandResult execCmd(final List<String> commands,
//                                        final List<String> envp,
//                                        final boolean isRooted) {
//        return execCmd(commands == null ? null : commands.toArray(new String[]{}),
//                envp == null ? null : envp.toArray(new String[]{}),
//                isRooted,
//                true);
//    }
//
//    /**
//     * Execute the command.
//     *
//     * @param commands The commands.
//     * @param isRooted True to use root, false otherwise.
//     * @return the single {@link CommandResult} instance
//     */
//    public static CommandResult execCmd(final String[] commands, final boolean isRooted) {
//        return execCmd(commands, isRooted, true);
//    }
//
//    /**
//     * Execute the command.
//     *
//     * @param command         The command.
//     * @param isRooted        True to use root, false otherwise.
//     * @param isNeedResultMsg True to return the message of result, false otherwise.
//     * @return the single {@link CommandResult} instance
//     */
//    public static CommandResult execCmd(final String command,
//                                        final boolean isRooted,
//                                        final boolean isNeedResultMsg) {
//        return execCmd(new String[]{command}, isRooted, isNeedResultMsg);
//    }
//
//    /**
//     * Execute the command.
//     *
//     * @param command         The command.
//     * @param envp            The environment variable settings.
//     * @param isRooted        True to use root, false otherwise.
//     * @param isNeedResultMsg True to return the message of result, false otherwise.
//     * @return the single {@link CommandResult} instance
//     */
//    public static CommandResult execCmd(final String command,
//                                        final List<String> envp,
//                                        final boolean isRooted,
//                                        final boolean isNeedResultMsg) {
//        return execCmd(new String[]{command}, envp == null ? null : envp.toArray(new String[]{}),
//                isRooted,
//                isNeedResultMsg);
//    }
//
//    /**
//     * Execute the command.
//     *
//     * @param command         The command.
//     * @param envp            The environment variable settings array.
//     * @param isRooted        True to use root, false otherwise.
//     * @param isNeedResultMsg True to return the message of result, false otherwise.
//     * @return the single {@link CommandResult} instance
//     */
//    public static CommandResult execCmd(final String command,
//                                        final String[] envp,
//                                        final boolean isRooted,
//                                        final boolean isNeedResultMsg) {
//        return execCmd(new String[]{command}, envp, isRooted, isNeedResultMsg);
//    }
//
//    /**
//     * Execute the command.
//     *
//     * @param commands        The commands.
//     * @param isRooted        True to use root, false otherwise.
//     * @param isNeedResultMsg True to return the message of result, false otherwise.
//     * @return the single {@link CommandResult} instance
//     */
//    public static CommandResult execCmd(final List<String> commands,
//                                        final boolean isRooted,
//                                        final boolean isNeedResultMsg) {
//        return execCmd(commands == null ? null : commands.toArray(new String[]{}),
//                isRooted,
//                isNeedResultMsg);
//    }
//
//    /**
//     * Execute the command.
//     *
//     * @param commands        The commands.
//     * @param isRooted        True to use root, false otherwise.
//     * @param isNeedResultMsg True to return the message of result, false otherwise.
//     * @return the single {@link CommandResult} instance
//     */
//    public static CommandResult execCmd(final String[] commands,
//                                        final boolean isRooted,
//                                        final boolean isNeedResultMsg) {
//        return execCmd(commands, null, isRooted, isNeedResultMsg);
//    }
//
//    /**
//     * Execute the command.
//     *
//     * @param commands        The commands.
//     * @param envp            Array of strings, each element of which
//     *                        has environment variable settings in the format
//     *                        <i>name</i>=<i>value</i>, or
//     *                        <tt>null</tt> if the subprocess should inherit
//     *                        the environment of the current process.
//     * @param isRooted        True to use root, false otherwise.
//     * @param isNeedResultMsg True to return the message of result, false otherwise.
//     * @return the single {@link CommandResult} instance
//     */
//    public static CommandResult execCmd(final String[] commands,
//                                        final String[] envp,
//                                        final boolean isRooted,
//                                        final boolean isNeedResultMsg) {
//        int result = -1;
//        if (commands == null || commands.length == 0) {
//            return new CommandResult(result, "", "");
//        }
//        Process process = null;
//        BufferedReader successResult = null;
//        BufferedReader errorResult = null;
//        StringBuilder successMsg = null;
//        StringBuilder errorMsg = null;
//        DataOutputStream os = null;
//        try {
//            process = Runtime.getRuntime().exec(isRooted ? "su" : "sh", envp, null);
//            os = new DataOutputStream(process.getOutputStream());
//            for (String command : commands) {
//                if (command == null) continue;
//                os.write(command.getBytes());
//                os.writeBytes(LINE_SEP);
//                os.flush();
//            }
//            os.writeBytes("exit" + LINE_SEP);
//            os.flush();
//            result = process.waitFor();
//            if (isNeedResultMsg) {
//                successMsg = new StringBuilder();
//                errorMsg = new StringBuilder();
//                successResult = new BufferedReader(
//                        new InputStreamReader(process.getInputStream(), "UTF-8")
//                );
//                errorResult = new BufferedReader(
//                        new InputStreamReader(process.getErrorStream(), "UTF-8")
//                );
//                String line;
//                if ((line = successResult.readLine()) != null) {
//                    successMsg.append(line);
//                    while ((line = successResult.readLine()) != null) {
//                        successMsg.append(LINE_SEP).append(line);
//                    }
//                }
//                if ((line = errorResult.readLine()) != null) {
//                    errorMsg.append(line);
//                    while ((line = errorResult.readLine()) != null) {
//                        errorMsg.append(LINE_SEP).append(line);
//                    }
//                }
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//        } finally {
//            try {
//                if (os != null) {
//                    os.close();
//                }
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//            try {
//                if (successResult != null) {
//                    successResult.close();
//                }
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//            try {
//                if (errorResult != null) {
//                    errorResult.close();
//                }
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//            if (process != null) {
//                process.destroy();
//            }
//        }
//        return new CommandResult(
//                result,
//                successMsg == null ? "" : successMsg.toString(),
//                errorMsg == null ? "" : errorMsg.toString()
//        );
//    }
//
//    /**
//     * The result of command.
//     */
//    public static class CommandResult {
//        public int result;
//        public String successMsg;
//        public String errorMsg;
//
//        public CommandResult(final int result, final String successMsg, final String errorMsg) {
//            this.result = result;
//            this.successMsg = successMsg;
//            this.errorMsg = errorMsg;
//        }
//
//        @Override
//        public String toString() {
//            return "result: " + result + "\n" +
//                    "successMsg: " + successMsg + "\n" +
//                    "errorMsg: " + errorMsg;
//        }
//    }
}
